﻿using System;
using System.ComponentModel;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Windows.Data;
using RrslLite.Net.Contracts;
using Binding = System.ServiceModel.Channels.Binding;
using Message = RrslLite.Net.Messages.Message;

namespace RrslLite.Net.Proxies
{
	public class AsyncMessageProcessorProxy : ClientBase<IAsyncWcfMessageService>, IAsyncWcfMessageService
	{
        public event EventHandler<AsyncCompletedEventArgs> OpenCompleted;

		public AsyncMessageProcessorProxy() {}
		public AsyncMessageProcessorProxy(string endpointConfigurationName) : base(endpointConfigurationName) { }
		public AsyncMessageProcessorProxy(string endpointConfigurationName, string remoteAddress) : base(endpointConfigurationName, remoteAddress) { }
		public AsyncMessageProcessorProxy(string endpointConfigurationName, EndpointAddress remoteAddress) : base(endpointConfigurationName, remoteAddress) { }
		public AsyncMessageProcessorProxy(Binding binding, EndpointAddress remoteAddress) : base(binding, remoteAddress) { }

		public IAsyncResult BeginInvokeOperations(Message[] requests, AsyncCallback callback, object asyncState)
		{
			return Channel.BeginInvokeOperations(requests, callback, asyncState);
		}


		Message[] IAsyncWcfMessageService.EndInvokeOperations(IAsyncResult result)
		{
			return Channel.EndInvokeOperations(result);
		}

		private IAsyncResult OnBeginInvokeOperations(object[] inValues, AsyncCallback callback, object asyncState)
		{
			var requests = ((Message[])(inValues[0]));
			return ((IAsyncWcfMessageService)(this)).BeginInvokeOperations(requests, callback, asyncState);
		}

		private object[] OnEndInvokeOperations(IAsyncResult result)
		{
			Message[] retVal = ((IAsyncWcfMessageService)(this)).EndInvokeOperations(result);
			return new object[] { retVal };
		}

		private void OnInvokeOperationsCompleted(object state)
		{
			var e = ((InvokeAsyncCompletedEventArgs)(state));
			((Action<InvokeOperationsAsyncCompletedArgs>)(e.UserState)).Invoke(new InvokeOperationsAsyncCompletedArgs(e.Results, e.Error, e.Cancelled, e.UserState));
		}

		public void InvokeOperationsAsync(Message[] messages, Action<InvokeOperationsAsyncCompletedArgs> operationsCompleted)
		{
			InvokeAsync(OnBeginInvokeOperations, new object[] { messages },
				OnEndInvokeOperations, OnInvokeOperationsCompleted, operationsCompleted);
		}

		private IAsyncResult OnBeginOpen(object[] inValues, AsyncCallback callback, object asyncState)
		{
			return ((ICommunicationObject)(this)).BeginOpen(callback, asyncState);
		}

		private object[] OnEndOpen(IAsyncResult result)
		{
			((ICommunicationObject)(this)).EndOpen(result);
			return null;
		}

		private void OnOpenCompleted(object state)
		{
			if ((OpenCompleted != null))
			{
				var e = ((InvokeAsyncCompletedEventArgs)(state));
                OpenCompleted(this, new AsyncCompletedEventArgs(e.Error, e.Cancelled, e.UserState));
			}
		}

		public void OpenAsync()
		{
			OpenAsync(null);
		}

		public void OpenAsync(object userState)
		{
			InvokeAsync(OnBeginOpen, null, OnEndOpen, OnOpenCompleted, userState);
		}

		private IAsyncResult OnBeginClose(object[] inValues, AsyncCallback callback, object asyncState)
		{
			return ((ICommunicationObject)(this)).BeginClose(callback, asyncState);
		}

		private object[] OnEndClose(IAsyncResult result)
		{
			((ICommunicationObject)(this)).EndClose(result);
			return null;
		}

		private void OnCloseCompleted(object state)
		{
			var e = ((InvokeAsyncCompletedEventArgs)(state));
			CloseCompleted(new AsyncCompletedEventArgs(e.Error, e.Cancelled, e.UserState));
		}

		public void CloseCompleted(AsyncCompletedEventArgs args)
		{
			if (args.Error != null)
			{
				Abort();
			}
		}

		public void CloseAsync()
		{
			CloseAsync(null);
		}

		public void CloseAsync(object userState)
		{
			InvokeAsync(OnBeginClose, null, OnEndClose, OnCloseCompleted, userState);
		}

		public void Dispose()
		{
			CloseAsync();
		}
	}


}